#include <jni.h>
#include <string>
#include<android/log.h>

extern "C"
JNIEXPORT jstring JNICALL
Java_com_lzh_desdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C" {
unsigned char DESKEY[8] = {0x57, 0x4A, 0x4C, 0x54, 0x58, 0x4B, 0x43, 0x4B};

enum {
    ENCRYPT = 0,     //加密
    DECRYPT  //解密
};
unsigned char const DesIp[] = {
        58, 50, 42, 34, 26, 18, 10, 2,
        60, 52, 44, 36, 28, 20, 12, 4,
        62, 54, 46, 38, 30, 22, 14, 6,
        64, 56, 48, 40, 32, 24, 16, 8,
        57, 49, 41, 33, 25, 17, 9, 1,
        59, 51, 43, 35, 27, 19, 11, 3,
        61, 53, 45, 37, 29, 21, 13, 5,
        63, 55, 47, 39, 31, 23, 15, 7
};


unsigned char const DesIp_1[] = {
        40, 8, 48, 16, 56, 24, 64, 32,
        39, 7, 47, 15, 55, 23, 63, 31,
        38, 6, 46, 14, 54, 22, 62, 30,
        37, 5, 45, 13, 53, 21, 61, 29,
        36, 4, 44, 12, 52, 20, 60, 28,
        35, 3, 43, 11, 51, 19, 59, 27,
        34, 2, 42, 10, 50, 18, 58, 26,
        33, 1, 41, 9, 49, 17, 57, 25
};


unsigned char const DesS[8][4][16] = {
        {
                {14, 4,  13, 1,  2,  15, 11, 8,  3,  10, 6,  12, 5,  9,  0,  7},
                {0,  15, 7,  4,  14, 2,  13, 1,  10, 6, 12, 11, 9,  5,  3,  8},
                {4,  1,  14, 8,  13, 6,  2,  11, 15, 12, 9,  7,  3,  10, 5,  0},
                {15, 12, 8,  2,  4,  9,  1,  7,  5,  11, 3,  14, 10, 0, 6,  13}
        },

        {
                {15, 1,  8,  14, 6,  11, 3,  4,  9,  7,  2,  13, 12, 0,  5,  10},
                {3,  13, 4,  7,  15, 2,  8,  14, 12, 0, 1,  10, 6,  9,  11, 5},
                {0,  14, 7,  11, 10, 4,  13, 1,  5,  8,  12, 6,  9,  3,  2,  15},
                {13, 8,  10, 1,  3,  15, 4,  2,  11, 6,  7,  12, 0,  5, 14, 9}
        },

        {
                {10, 0,  9,  14, 6,  3,  15, 5,  1,  13, 12, 7,  11, 4,  2,  8},
                {13, 7,  0,  9,  3,  4,  6,  10, 2,  8, 5,  14, 12, 11, 15, 1},
                {13, 6,  4,  9,  8,  15, 3,  0,  11, 1,  2,  12, 5,  10, 14, 7},
                {1,  10, 13, 0,  6,  9,  8,  7,  4,  15, 14, 3,  11, 5, 2,  12}
        },

        {
                {7,  13, 14, 3,  0,  6,  9,  10, 1,  2,  8,  5,  11, 12, 4,  15},
                {13, 8,  11, 5,  6,  15, 0,  3,  4,  7, 2,  12, 1,  10, 14, 9},
                {10, 6,  9,  0,  12, 11, 7,  13, 15, 1,  3,  14, 5,  2,  8,  4},
                {3,  15, 0,  6,  10, 1,  13, 8,  9,  4,  5,  11, 12, 7, 2,  14}
        },

        {
                {2,  12, 4,  1,  7,  10, 11, 6,  8,  5,  3,  15, 13, 0,  14, 9},
                {14, 11, 2,  12, 4,  7,  13, 1,  5,  0, 15, 10, 3,  9,  8,  6},
                {4,  2,  1,  11, 10, 13, 7,  8,  15, 9,  12, 5,  6,  3,  0,  14},
                {11, 8,  12, 7,  1,  14, 2,  13, 6,  15, 0,  9,  10, 4, 5,  3}
        },

        {
                {12, 1,  10, 15, 9,  2,  6,  8,  0,  13, 3,  4,  14, 7,  5,  11},
                {10, 15, 4,  2,  7,  12, 9,  5,  6,  1, 13, 14, 0,  11, 3,  8},
                {9,  14, 15, 5,  2,  8,  12, 3,  7,  0,  4,  10, 1,  13, 11, 6},
                {4,  3,  2,  12, 9,  5,  15, 10, 11, 14, 1,  7,  6,  0, 8,  13}
        },

        {
                {4,  11, 2,  14, 15, 0,  8,  13, 3,  12, 9,  7,  5,  10, 6,  1},
                {13, 0,  11, 7,  4,  9,  1,  10, 14, 3, 5,  12, 2,  15, 8,  6},
                {1,  4,  11, 13, 12, 3,  7,  14, 10, 15, 6,  8,  0,  5,  9,  2},
                {6,  11, 13, 8,  1,  4,  10, 7,  9,  5,  0,  15, 14, 2, 3,  12}
        },

        {
                {13, 2,  8,  4,  6,  15, 11, 1,  10, 9,  3,  14, 5,  0,  12, 7},
                {1,  15, 13, 8,  10, 3,  7,  4,  12, 5, 6,  11, 0,  14, 9,  2},
                {7,  11, 4,  1,  9,  12, 14, 2,  0,  6,  10, 13, 15, 3,  5,  8},
                {2,  1,  14, 7,  4,  10, 8,  13, 15, 12, 9,  0,  3,  5, 6,  11}
        }
};


unsigned char const DesE[] = {
        32, 1, 2, 3, 4, 5,
        4, 5, 6, 7, 8, 9,
        8, 9, 10, 11, 12, 13,
        12, 13, 14, 15, 16, 17,
        16, 17, 18, 19, 20, 21,
        20, 21, 22, 23, 24, 25,
        24, 25, 26, 27, 28, 29,
        28, 29, 30, 31, 32, 1
};


unsigned char const DesP[] = {
        16, 7, 20, 21,
        29, 12, 28, 17,
        1, 15, 23, 26,
        5, 18, 31, 10,
        2, 8, 24, 14,
        32, 27, 3, 9,
        19, 13, 30, 6,
        22, 11, 4, 25
};


unsigned char const DesPc_1[] = {
        57, 49, 41, 33, 25, 17, 9,
        1, 58, 50, 42, 34, 26, 18,
        10, 2, 59, 51, 43, 35, 27,
        19, 11, 3, 60, 52, 44, 36,
        63, 55, 47, 39, 31, 23, 15,
        7, 62, 54, 46, 38, 30, 22,
        14, 6, 61, 53, 45, 37, 29,
        21, 13, 5, 28, 20, 12, 4
};


unsigned char const DesPc_2[] = {
        14, 17, 11, 24, 1, 5,
        3, 28, 15, 6, 21, 10,
        23, 19, 12, 4, 26, 8,
        16, 7, 27, 20, 13, 2,
        41, 52, 31, 37, 47, 55,
        30, 40, 51, 45, 33, 48,
        44, 49, 39, 56, 34, 53,
        46, 42, 50, 36, 29, 32
};


unsigned char const DesRots[] = {
        1, 1, 2, 2,
        2, 2, 2, 2,
        1, 2, 2, 2,
        2, 2, 2, 1,
        0
};


////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////以下声明本文件中使用的私有函数//////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
void movram(unsigned char *source, unsigned char *target, unsigned char length);
void doxor(unsigned char *sourceaddr, unsigned char *targetaddr, unsigned char length);
void setbit(unsigned char *dataddr, unsigned char pos, unsigned char b0);
unsigned char getbit(unsigned char *dataddr, unsigned char pos);
void selectbits(unsigned char *source, unsigned char const *table, unsigned char *target,
                unsigned char count);
void shlc(unsigned char *data_p);
void shrc(unsigned char *data_p);
void strans(unsigned char *index, unsigned char *target);
void des(unsigned char *data_p, unsigned char *key_p, char type);
void CounKey(unsigned char *TemBuf);


////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////以下定义本文件中使用的私有函数//////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
void movram(unsigned char *source, unsigned char *target, unsigned char length) {
    unsigned char i;

    for (i = 0; i < length; i++)/*移动数据块*/
    {
        target[i] = source[i];
    }
}

void doxor(unsigned char *sourceaddr, unsigned char *targetaddr, unsigned char length) {
    unsigned char i;

    for (i = 0; i < length; i++)/*求异或*/
    {
        sourceaddr[i] ^= targetaddr[i];
    }
}

void setbit(unsigned char *dataddr, unsigned char pos, unsigned char b0) {
    unsigned char byte_count;
    unsigned char bit_count;
    unsigned char temp;

    temp = 1;
    byte_count = (pos - 1) / 8;
    bit_count = 7 - ((pos - 1) % 8);
    temp <<= bit_count;

    if (b0) {
        dataddr[byte_count] |= temp;
    } else {
        temp = ~temp;
        dataddr[byte_count] &= temp;
    }
}


unsigned char getbit(unsigned char *dataddr, unsigned char pos) {
    unsigned char byte_count;
    unsigned char bit_count;
    unsigned char temp;

    temp = 1;
    byte_count = (pos - 1) / 8;
    bit_count = 7 - ((pos - 1) % 8);
    temp <<= bit_count;
    if (dataddr[byte_count] & temp) {
        return (1);
    } else {
        return (0);
    }
}


void selectbits(unsigned char *source, unsigned char const *table, unsigned char *target,
                unsigned char count) {
    unsigned char i;

    for (i = 0; i < count; i++) {
        setbit(target, i + 1, getbit(source, table[i]));
    }
}


void shlc(unsigned char *data_p) {
    unsigned char i, b0;

    b0 = getbit(data_p, 1);

    for (i = 0; i < 7; i++) {
        data_p[i] <<= 1;

        if (i != 6) {
            setbit(&data_p[i], 8, getbit(&data_p[i + 1], 1));
        }
    }

    setbit(data_p, 56, getbit(data_p, 28));
    setbit(data_p, 28, b0);
}


void shrc(unsigned char *data_p) {
    unsigned char b0;
    int i;

    b0 = getbit(data_p, 56);

    for (i = 6; i >= 0; i--) {
        data_p[i] >>= 1;

        if (i != 0) {
            setbit(&data_p[i], 1, getbit(&data_p[i - 1], 8));
        }
    }

    setbit(data_p, 1, getbit(data_p, 29));
    setbit(data_p, 29, b0);
}


/* The problem is about yielded in this function */
void strans(unsigned char *index, unsigned char *target) {
    unsigned char row, line, t, i, j; //,b0,b1;

    for (i = 0; i < 4; i++) {
        row = line = t = 0;
//		setbit(&line,7,b0 = getbit(index,i * 12 + 1));
//		setbit(&line,8,b1 = getbit(index,i * 12 + 6));
        setbit(&line, 7, getbit(index, i * 12 + 1));
        setbit(&line, 8, getbit(index, i * 12 + 6));

        for (j = 2; j < 6; j++) {
            setbit(&row, 3 + j, getbit(index, i * 12 + j));
        }

        t = DesS[i * 2][line][row];
        t <<= 4;
        line = row = 0;
        setbit(&line, 7, getbit(index, i * 12 + 7));
        setbit(&line, 8, getbit(index, i * 12 + 12));

        for (j = 2; j < 6; j++) {
            setbit(&row, 3 + j, getbit(index, i * 12 + 6 + j));
        }

        t |= DesS[i * 2 + 1][line][row];
        target[i] = t;
    }
}


////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////以下定义本文件中使用的公共函数//////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
void des(unsigned char *data_p, unsigned char *key_p, char type) {
    unsigned char tempbuf[12];
    unsigned char key[7];
    unsigned char i;
    unsigned char j;
    unsigned char count;
    void (*f)(unsigned char *data_p);

    selectbits(data_p, DesIp, tempbuf, 64);/*初始变换*/
    movram(tempbuf, data_p, 8);
    selectbits(key_p, DesPc_1, key, 56);/*KEY的初始变换*/

    for (i = 0; i < 16; i++) {
        selectbits(data_p + 4, DesE, tempbuf, 48);/*膨胀变换*/

        if (type == ENCRYPT)//DES_OPERATE_TYPE_ENCRYPT)
        {
            f = shlc;
            count = i;
        } else {
            count = 16 - i;
            f = shrc;
        }

        for (j = 0; j < DesRots[count]; j++)/*KEY 的移位*/
        {
            f(key);
        }

        selectbits(key, DesPc_2, tempbuf + 6, 48);/*KEY 压缩变换*/
        doxor(tempbuf, tempbuf + 6, 6);
        strans(tempbuf, tempbuf + 6);
        selectbits(tempbuf + 6, DesP, tempbuf, 32);
        doxor(tempbuf, data_p, 4);

        if (i < 15) {
            movram(data_p + 4, data_p, 4);
            movram(tempbuf, data_p + 4, 4);
        }
    }

    movram(tempbuf, data_p, 4);
    selectbits(data_p, DesIp_1, tempbuf, 64);
    movram(tempbuf, data_p, 8);
}


void CounKey(unsigned char *TemBuf) {
    des(TemBuf, DESKEY, DECRYPT);
}

void DesXor(unsigned char *buf) {
    unsigned char i;
    for (i = 0; i < 8; i++) {
        buf[i] = buf[i] ^ 0x55;
    }

}

unsigned char Get_Bcc(unsigned char *dat,unsigned char len) {
    unsigned char i = 0;
    unsigned char bcc = 0;

    for (i = 0; i < len; i++)
        bcc ^= *(dat + i);

    return bcc;
}

//解密
JNIEXPORT jbyteArray JNICALL
Java_com_lzh_des_1lib_DesUtil__1decryption(JNIEnv *env, jclass type, jbyteArray value_) {
    jbyte *data = env->GetByteArrayElements(value_, NULL);

    des((unsigned char *) data, DESKEY, DECRYPT);

    env->ReleaseByteArrayElements(value_, data, 0);
    return value_;
}

//加密
JNIEXPORT jbyteArray JNICALL
Java_com_lzh_des_1lib_DesUtil__1encryption(JNIEnv *env, jclass type, jbyteArray value_) {
    jbyte *data = env->GetByteArrayElements(value_, NULL);

    des((unsigned char *) data, DESKEY, ENCRYPT);

    env->ReleaseByteArrayElements(value_, data, 0);
    return value_;
}

//解密并异或
JNIEXPORT jbyteArray JNICALL
Java_com_lzh_des_1lib_DesUtil__1decryXor(JNIEnv *env, jclass type, jbyteArray value_) {
    jbyte *data = env->GetByteArrayElements(value_, NULL);

    CounKey((unsigned char *) data);
    DesXor((unsigned char *) data);

    env->ReleaseByteArrayElements(value_, data, 0);
    return value_;
}

JNIEXPORT jbyte JNICALL
Java_com_lzh_des_1lib_DesUtil_xorSum(JNIEnv *env, jclass type, jbyteArray value_) {
    jbyte *value = env->GetByteArrayElements(value_, NULL);

    char result = Get_Bcc((unsigned char *) value, (unsigned char) env->GetArrayLength(value_));

    env->ReleaseByteArrayElements(value_, value, 0);

    return result;
}

}
